// 撤销恢复使用的栈
import { OperateType } from "./Constants";
import Block from "./features/Block"
import { GridSystem } from "./Index";
import IStatus from "./interface/IStatus";

class Stack {

    stackList: IStatus[][]  // gls中所有的元素放到stackList中
    pointer: number  // 指针
    constructor() {
        this.stackList = []
        this.pointer = this.stackList.length - 1;
    }

    push(blocks: Block[]) {
        while (this.pointer != this.stackList.length - 1) {  // 如果push前指针不指向末尾,即被undo或restore过,那么就先删除pointer之后的记录
            this.stackList.pop();
        }
        let iStatus: IStatus[] = []
        blocks.forEach(block => {
            // console.log(this.pointer);
            let type = OperateType.UPDATE;
            if (!this.stackList[this.pointer]) {
                type = OperateType.ADD
            }
            if (this.stackList[this.pointer] && this.stackList[this.pointer].every(nodeStatus => nodeStatus.id != block.id)) {
                type = OperateType.ADD
            }
            iStatus.push({  // 只记录部分属性,跟操作有关的,防止属性过多占内存
                id: block.id,
                class: block.class,
                x: block.x,
                y: block.y,
                width: block.width,
                height: block.height,
                angle: block.angle,
                text: block.text,
                src: block.src,
                type
            })
        })
        this.stackList[this.pointer] && this.stackList[this.pointer].forEach(nodeStatus => {
            if (!blocks.some(block => block.id == nodeStatus.id)) {
                nodeStatus.type = OperateType.DEL
            } else if (nodeStatus.type == OperateType.DEL) {
                // nodeStatus.type = OperateType.ADD
            }
        })
        this.stackList.push(iStatus);
        this.pointer = this.stackList.length - 1;
        // localStorage.setItem("stageInfo", JSON.stringify(this.stackList[this.pointer]))
    }

    undo(blocks: Block[], fn?: Function) {  // 撤销
        if (this.pointer > 0) {
            this.pointer--;
        } else {
            return
        }
        let needDelNodes = this.stackList[this.pointer + 1] && this.stackList[this.pointer + 1].filter(nodeStatus => nodeStatus.type == OperateType.ADD)
        let needAddNodes = this.stackList[this.pointer] && this.stackList[this.pointer].filter(nodeStatus => nodeStatus.type == OperateType.DEL)
            this.stackList[this.pointer+1] && this.stackList[this.pointer+1].forEach(item=>{
                if(this.stackList[this.pointer] && !this.stackList[this.pointer].find(ele=>ele.id == item.id)){
                    needDelNodes.push(item)
                }
            })
        this.setProp(blocks, needDelNodes, needAddNodes)
        needAddNodes.forEach(item => {
            item.type = OperateType.DEL
        })
        needDelNodes.forEach(item => {
            item.type = OperateType.ADD
        })
        fn && fn();
    }

    restore(blocks: Block[], fn?: Function) {  // 恢复
        if (this.pointer < this.stackList.length - 1) {
            this.pointer++;
        } else {
            return
        }
        let needDelNodes = this.stackList[this.pointer - 1] && this.stackList[this.pointer - 1].filter(nodeStatus => nodeStatus.type == OperateType.DEL)
        let needAddNodes = this.stackList[this.pointer] && this.stackList[this.pointer].filter(nodeStatus => nodeStatus.type == OperateType.ADD)

        this.setProp(blocks, needDelNodes, needAddNodes)
        needAddNodes.forEach(item => {
            item.type = OperateType.ADD
        })
        needDelNodes.forEach(item => {
            item.type = OperateType.DEL
        })
        fn && fn();
    }

    setProp(blocks: Block[], needDelNodes: IStatus[] = [], needAddNodes: IStatus[] = []) {  // 重置属性
        needAddNodes.forEach(item => {   // 重新创建被删除的元素
            let block: Block | null = GridSystem.createFetureByClass(item)
            if (block) {
                item.id && (block.id = item.id);
                blocks.push(block)
            } else {
                throw "创建失败!"
            }
        })

        for (let index = blocks.length - 1; index >= 0; index--) {
            const block = blocks[index];
            if (needDelNodes.find(nodeStatus => nodeStatus.id == block.id)) {
                blocks.splice(index, 1)
            }
            let fetureStatus = this.stackList[this.pointer].find(nodeStatus => nodeStatus.id === block.id);
            if (fetureStatus) {
                block.x = fetureStatus.x;
                block.y = fetureStatus.y;
                block.width = fetureStatus.width;
                block.height = fetureStatus.height;
                block.angle = fetureStatus.angle || 0;
            }
        }
    }

}

export default Stack;